package bancosys.tec.services.input.driver;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import jmine.tec.services.ServicesController;
import jmine.tec.services.api.ServicesPage;
import jmine.tec.services.api.execution.ServicesPageExecutor;
import jmine.tec.services.io.ServicesPageBean;
import jmine.tec.services.io.ServicesReader;

import org.springframework.beans.factory.InitializingBean;

import bancosys.tec.datadigester.DefaultDigesterFile;
import bancosys.tec.datadigester.DigesterDriver;
import bancosys.tec.services.input.driver.bean.ServicePageHeader;
import bancosys.tec.services.input.driver.processor.ThreadSafeServiceProcessor;
import bancosys.tec.services.input.driver.xls.ServiceXLSDriver;
import bancosys.tec.services.input.driver.xml.ServiceXMLDriver;

/**
 * Implementacao da interface {@link ServicesReader} que utiliza como fonte de dados um Driver de arquivo.
 * 
 * @author Rafael Volpato
 */
public final class DigesterDriverServicesReader implements ServicesReader, InitializingBean {

    private ThreadSafeServiceProcessor serviceProcessor;

    private ServicesPageExecutor servicesPageExecutor;

    private ServicesController controller;

    /**
     * Construtor padrao.
     * 
     * @param controller controller
     * @param servicesPageExecutor servicesPageExecutor
     */
    public DigesterDriverServicesReader(ServicesController controller, ServicesPageExecutor servicesPageExecutor) {
        this.servicesPageExecutor = servicesPageExecutor;
        this.controller = controller;
        try {
            this.afterPropertiesSet();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Construtor sem parametros.
     */
    public DigesterDriverServicesReader() {

    }

    /**
     * {@inheritDoc}
     */
    public void afterPropertiesSet() throws Exception {
        this.serviceProcessor = new ThreadSafeServiceProcessor(this.controller, this.servicesPageExecutor);
    }

    /**
     * {@inheritDoc}
     */
    public List<ServicesPageBean> readServicesPageBean(String fileName, InputStream inputStream) throws IOException {
        ServicePageHeader bean = this.readServicePageHeader(fileName, inputStream);
        return bean.getWorkSheets();
    }

    /**
     * {@inheritDoc}
     */
    public List<ServicesPage> readServices(String fileName, InputStream inputStream) throws IOException {
        ServicePageHeader bean = this.readServicePageHeader(fileName, inputStream);
        return this.serviceProcessor.getServicesPages(bean);
    }

    /**
     * Utiliza a implementação de drivers (digester-driver) para executar a leitura da {@link URL} informada.
     * 
     * @param fileName o nome do arquivo
     * @param inputStream o conteúdo do arquivo
     * @return {@link ServicePageHeader}
     * @throws IOException se ocorrer algum erro
     */
    private ServicePageHeader readServicePageHeader(String fileName, InputStream inputStream) throws IOException {
        DigesterDriver<ServicePageHeader> driver = this.findDigesterDriver(fileName);
        Map<String, String> map = Collections.emptyMap();
        ServicePageHeader bean = driver.parse(new DefaultDigesterFile(fileName, inputStream), map);
        bean.setFileName(fileName);
        return bean;
    }

    /**
     * Factory method responsavel por informar o driver que vai tratar o arquivo passado como parametro.
     * 
     * @param fileName o nome do arquivo
     * @return driver que deve ser utilizado para tratar o arquivo passado como parametro
     */
    private DigesterDriver<ServicePageHeader> findDigesterDriver(String fileName) {
        DigesterDriver<ServicePageHeader> driver = null;

        if (fileName.matches(ServicesReader.XLS_REGEX)) {
            driver = new ServiceXLSDriver();
        } else if (fileName.matches(ServicesReader.XML_REGEX)) {
            driver = new ServiceXMLDriver();
        } else {
            throw new IllegalArgumentException("Nao foi possivel encontrar o driver correspondente para o arquivo '" + fileName + "'!");
        }
        return driver;
    }

    /**
     * @param servicesPageExecutor the servicesPageExecutor to set
     */
    public void setServicesPageExecutor(ServicesPageExecutor servicesPageExecutor) {
        this.servicesPageExecutor = servicesPageExecutor;
    }

    /**
     * @param controller the controller to set
     */
    public void setController(ServicesController controller) {
        this.controller = controller;
    }
}
